﻿using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.ComponentModel;
using System.Reflection;
using System.Text;

namespace Pay.Core
{
	/// <summary>
	/// EnumSchemeFilter
	/// </summary>
	public class EnumSchemeFilter : ISchemaFilter
	{
		public void Apply(OpenApiSchema schema, SchemaFilterContext context)
		{
			var enumType = GetNullableEnum(context.Type);
			if (context.Type.IsEnum || enumType != null)
			{
				schema.Description = ToEnumDesc(enumType ?? context.Type);
				schema.Type = context.Type.IsEnum ? context.Type.Name : enumType.Name;
				schema.Format = schema.Type;
				EnumDescriptionList.Dic.TryAdd(schema.Type, schema.Description);
			}
		}

		#region private methods
		/// <summary>
		/// 获取可空类型枚举参数，无返回nu..
		/// </summary>
		private Type GetNullableEnum(Type type)
		{
			if (type.IsReferenceOrNullableType())
			{
				return type.GenericTypeArguments.FirstOrDefault(m => m.IsEnum);
			}

			return null;
		}

		/// <summary>
		/// 拼接信息
		/// </summary>
		private string ToEnumDesc(Type type)
		{
			var stringBuilder = new StringBuilder();
			Enum.GetNames(type)
				.ToList()
				.ForEach(name =>
				{
					var e = (Enum)Enum.Parse(type, name);
					var data = $"{Convert.ToInt64(Enum.Parse(type, name))} {ToDescription(e)}、";

					stringBuilder.Append(data);
				});
			return stringBuilder.ToString().TrimEnd('、');
		}

		/// <summary>
		/// 获取枚举描述
		/// </summary>
		/// <param name="value">enum</param>
		/// <returns></returns>
		private string ToDescription(Enum value)
		{
			var type = value.GetType();
			var name = Enum.GetName(type, value);
			if (string.IsNullOrWhiteSpace(name))
			{
				return value.ToString();
			}

			var field = type.GetField(name);
			var description = field?.GetCustomAttribute<DescriptionAttribute>();
			return description == null ? value.ToString() : description.Description;
		}
		#endregion
	}

	/// <summary>
	/// swagger 枚举数据存储类
	/// </summary>
	public class EnumDescriptionList
	{
		/// <summary>
		/// 枚举描述字典：key->枚举名称；value:所有枚举值及对应描述
		/// </summary>
		public static Dictionary<string, string> Dic = new Dictionary<string, string>();
	}
}
